package socket.selectorThread;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.Channel;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.atomic.AtomicInteger;

public class SelectorThreadGroup {
  
  SelectorThread[] selectorThreads;
  ServerSocketChannel server = null;
  AtomicInteger count = new AtomicInteger();
  
  // 这是一个 work
  SelectorThreadGroup stg = this;
  
  public void setWorker(SelectorThreadGroup stg) {
    this.stg = stg;
  }
  
  // 无论是 boss端 以及client 端 都会启动多个线程 来执行 SelectorThread
  SelectorThreadGroup(int num) throws IOException {
    this.selectorThreads = new SelectorThread[num];
    
    for (int i = 0; i < num; i++) {
      this.selectorThreads[i] = new SelectorThread(this);
      
      // 尝试开启 一个线程
      new Thread(this.selectorThreads[i]).start();
    }
  }
  
  // 启动 多个服务端
  public void bind(int port) throws IOException {
    // 开启一个 server socket
    server = ServerSocketChannel.open();
    // 设置 server 非阻塞
    server.configureBlocking(false);
    // server 服务 绑定端口
    server.bind(new InetSocketAddress(port));

//    nextSelector(server);
    nextSelectorV3(server);
  }
  
  public void nextSelectorV3(Channel c) {
    try {
      // 这是 服务器端 反之 就是客户端
      SelectorThread st;
      if (c instanceof ServerSocketChannel) {
        // 以轮训的方式 拿到下一个 SelectorThread
        st = next();
        st.queue.add(c);
        st.setWorker(stg);
      } else {
        st = nextV3();
        
        st.queue.add(c);
      }
      st.selector.wakeup();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  // 此时的 c 就是 ServerSocketChannel
  public void nextSelector(Channel c) {
    // 这是 下一个 Selector
    SelectorThread nextSelector = next();
    
    // 通过 队列 添加 channel
    nextSelector.queue.add(c);
    // 通过打断阻塞，让对应的线程去自己在打断后完成注册selector
    nextSelector.selector.wakeup();
  }
  
  private SelectorThread next() {
    // 采用 轮训的方式 来选择下一个 Selector
    int nextIndex = count.incrementAndGet() % selectorThreads.length;
    return this.selectorThreads[nextIndex];
  }
  
  private SelectorThread nextV3() {
    int index = count.incrementAndGet() % stg.selectorThreads.length;
    return stg.selectorThreads[index];
  }
}
